/**
 * @file binary_tree.hpp
 * @author 逆流 (1171267147@qq.com)
 * @brief
 * @version 0.1
 * @date 2024-10-15
 *
 * @copyright Copyright (c) 2024
 *
 */

#ifndef INC_STL_BINARY_TREE_HPP_
#define INC_STL_BINARY_TREE_HPP_

#include <functional>
#include <iostream>

#include "node.h"

namespace stl {

template <typename T>
class BinaryTree {
public:
    BinaryTree() : root_(nullptr) {}
    virtual ~BinaryTree() {
        // TODO(yangjian): Implement a proper destructor to free the tree nodes
    }

    std::size_t size() const { return size_; }

    bool Empty() { return nullptr == root_; }

    virtual void Push(T data) = 0;
    virtual T    Pop()        = 0;

    virtual void Clear() = 0;

    void Preorder(const std::function<void(T)> &func) { Preorder(root_, func); }

    void Inorder(const std::function<void(T)> &func) { Inorder(root_, func); }

    void Postorder(const std::function<void(T)> &func) { Postorder(root_, func); }

protected:
    virtual void Remove(BinaryTreeNode<T> *node) {
        if (nullptr == node) {
            return;
        }
        Remove(node->left);
        Remove(node->right);
        delete node;
        node = nullptr;
        this->size_--;
    }

    BinaryTreeNode<T> *root_;
    std::size_t        size_;

private:
    void Preorder(BinaryTreeNode<T> *root, const std::function<void(T)> &func) {
        if (nullptr != root) {
            if (func) {
                func(root->data);
            } else {
                std::cout << root->data << " ";
            }
            Preorder(root->left, func);
            Preorder(root->right, func);
        }
    }

    void Inorder(BinaryTreeNode<T> *root, const std::function<void(T)> &func) {
        if (nullptr != root) {
            Inorder(root->left, func);
            if (func) {
                func(root->data);
            } else {
                std::cout << root->data << " ";
            }
            Inorder(root->right, func);
        }
    }

    void Postorder(BinaryTreeNode<T> *root, const std::function<void(T)> &func) {
        if (nullptr != root) {
            Postorder(root->left, func);
            Postorder(root->right, func);
            if (func) {
                func(root->data);
            } else {
                std::cout << root->data << " ";
            }
        }
    }
};
}  // namespace stl

#endif  // INC_STL_BINARY_TREE_HPP_
